#![no_std]
use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use atomic_polyfill::{AtomicBool, Ordering};
pub struct StaticCell<T> {
used: AtomicBool,
val: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T> Send for StaticCell<T> {}
unsafe impl<T> Sync for StaticCell<T> {}
impl<T> StaticCell<T> {
#[inline(always)]
pub const fn new() -> Self {
Self {
used: AtomicBool::new(false),
val: UnsafeCell::new(MaybeUninit::uninit()),
}
}
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn put(&self, val: T) -> &mut T {
self.put_with(|| val)
}
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn put_with(&self, val: impl FnOnce() -> T) -> &mut T {
if self
.used
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
panic!("PutCell::put() called multiple times");
}
let p: &mut MaybeUninit<T> = unsafe { &mut *self.val.get() };
p.write(val())
}
}
impl<T> Drop for StaticCell<T> {
fn drop(&mut self) {
if self.used {
unsafe { self.val.get().assume_init_drop() }
}
}
}